package com.zhijian.warehouse.manage.service.sse;

import com.zhijian.BusinessException;
import com.zhijian.response.enums.ResponseCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 *
 * @Author wxy
 * @Version 1.0.1
 */
@Slf4j
@Component
public class SseClient {
    //TODO clus待定
    private static Map<String, SseEmitter> clientMap = new ConcurrentHashMap<>();
    //private static Map<String, SseMessage> sseMessageMap = new ConcurrentHashMap<>();

    /**
     * 获取客户端列表
     * @return
     */
    public String[] getClientIds() {
        return clientMap.keySet().toArray(new String[0]);
    }

    /**
     * 打开链接，默认返回连接成功标识
     * @param clientId 客户端Id
     * @return
     */
    public SseEmitter connect(String clientId) {
        return connect(clientId, new ConnectedHandler() {
            @Override
            public SseMessage handle(String clientId) {
                return SseMessage.builder().type(0).data("connected").build();
            }
        });
    }

    /**
     * 打开链接
     * @param clientId 客户端Id
     * @param handler  链接操作
     * @return
     */
    public SseEmitter connect(String clientId, ConnectedHandler handler) {
        Long i = 2000L;//2秒后丢弃
        // 获取或者创建SseEmitter实例
        SseEmitter emitter;
        if (clientMap.containsKey(clientId)) {
            emitter = clientMap.get(clientId);
        } else {
            emitter = new SseEmitter(i);
            clientMap.put(clientId, emitter);
        }
        try {
            emitter.send(SseEmitter.event().id(clientId).data(handler.handle(clientId)));

        } catch (IOException ex) {
            log.error("{}| connect error", clientId, ex);
            throw new BusinessException(ResponseCodeEnum.FAILURE);
        }
        emitter.onCompletion(() -> {
            clientMap.remove(clientId);
        });
        emitter.onTimeout(() -> {
            clientMap.remove(clientId);
        });
        emitter.onError((throwable) -> {
            clientMap.remove(clientId);
        });
        clientMap.put(clientId, emitter);
        log.info("{}| connected success", clientId);
        return emitter;
    }

    /**
     * 发送消息
     * @param clientId
     * @param message
     */
    public void send(String clientId, SseMessage message) {
        SseEmitter emitter = clientMap.get(clientId);
        if (emitter == null) {
            log.warn("{}| no matched client and skiped", clientId);
            return;
        }
        try {
            emitter.send(message, MediaType.APPLICATION_JSON);
        } catch (Exception ex) {
            log.error("{}| send message error {}", clientId, message);
            //TODO 补充失败过多自动移除，绑定clientId，暂跳过
        }
    }

    /**
     * 发送消息
     * @param clientId
     */
    public SseEmitter send(String clientId) {
       return clientMap.get(clientId);
    }
}
